package eu.jk.performance.buffer;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;

import eu.jk.performance.buffer.swap.SwapFile;
import eu.jk.performance.buffer.swap.SwapFileFactory;

public class BufferPoolNosync<T> implements BufferPool<T> {
	/**
	 * key->index索引
	 */
	HashMap<String, Integer> indexMap = new HashMap<String, Integer>();
	/**
	 * index->key索引
	 */
	String[] keyMap = null;
	/**
	 * RAM缓存存储数组
	 */
	BufferedObject<T>[] pool = null;
	/**
	 * 转储缓存的索引
	 */
	HashMap<String, Integer> swapMap = new HashMap<String, Integer>();
	/**
	 * 转储文件
	 */
	SwapFile<T> swapFile;
	/**
	 * 内部指针
	 */
	Integer index = 0;
	/**
	 * RAM缓存大小
	 */
	int size = 0;
	/**
	 * 已使用RAM缓存
	 */
	int usedSize = 0;

	@SuppressWarnings("unchecked")
	BufferPoolNosync(int size) {
		this.size = size;
		swapFile = new SwapFileFactory<T>().newSwapFile("test");
		pool = new BufferedObject[size];
		keyMap = new String[size];
	}

	@Override
	public void put(String key, T value) {
		// 未满，直接添加
		if (usedSize < size) {
			index = index % size;
			pool[index] = new BufferedObject<T>(value);
			indexMap.put(key, index);// 设置key->index
			keyMap[index] = key;// index->key
			usedSize++;
			index++;
			return;
		}
		// 满了，查找替换
		int searchCount = 0;
		BufferedObject<T> old = null;
		long time = System.currentTimeMillis();
		while (searchCount < size) {
			searchCount++;
			index = index % size;
			old = pool[index];
			if (old.getLastAccess() + RuntimeConfigure.getMaxExpire() < time) {
				break; // index chosen
			}
			index++;
		}
		// 如果没有超期资源，置换当前资源
		// 置换操作
		index = index % size;
		old = pool[index];
		// 对象放到RAM中
		pool[index] = new BufferedObject<T>(value);
		String oldKey = keyMap[index];
		indexMap.remove(keyMap[index]);// 移除原有key
		indexMap.put(key, index);// 设置key->index
		keyMap[index] = key;// index->key
		index++;
		if (old.getObject() instanceof Serializable) {
			// 可交换，交换
			int si = 0;
			try {
				si = swapFile.swapIn((Serializable) old.getObject());
			} catch (IOException e) {
				e.printStackTrace();
			}
			swapMap.put(oldKey, si);
		}
	}

	@Override
	public T get(String key) {
		Integer i = indexMap.get(key);
		if (i != null) {
			return pool[i].getObject();
		}
		Integer si = swapMap.get(key);
		if (si == null)
			return null;
		// 备注，如果Swap中存在配对，表示T是Swapable的子类
		// 查找替换
		int searchCount = 0;
		BufferedObject<T> old = null;
		long time = System.currentTimeMillis();
		while (searchCount < size) {
			searchCount++;
			index = index % size;
			old = pool[index];
			if (old.getLastAccess() + RuntimeConfigure.getMaxExpire() < time) {
				break; // index chosen
			}
			index++;
		}
		index = index % size;
		old = pool[index];
		// 交换
		T swapOut = null;
		try {
			swapOut = swapFile.swapOut(si);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		String o_key = keyMap[index];
		// 清除原来的Map
		swapMap.remove(key);
		indexMap.remove(o_key);
		// 更新Map、交换对象
		keyMap[index] = key;
		indexMap.put(key, index);
		try {
			swapMap.put(o_key,
					swapFile.swapIn((Serializable) pool[index].getObject()));
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		pool[index] = new BufferedObject<T>(swapOut);
		return swapOut;
	}

	@Override
	public T remove(String key) {
		Integer i = indexMap.get(key);
		if (i != null) {
			indexMap.remove(keyMap[i]);
			keyMap[i] = null;
			T o = pool[i].getObject();
			pool[i] = null;
			return o;
		}
		i = swapMap.remove(key);
		if (i == null)
			return null;
		try {
			return swapFile.swapOut(i);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public boolean contains(String key) {
		if (indexMap.containsKey(key))
			return true;
		if (swapMap.containsKey(key))
			return true;
		return false;
	}

	@Override
	public int getFreeSize() {
		return size - usedSize;
	}

	@Override
	public int getTotalSize() {
		return size;
	}

	@Override
	public int getUsedSize() {
		return usedSize;
	}

	@Override
	public void resize(int size) {
		// TODO Auto-generated method stub

	}

	@Override
	public void close() {
		swapFile.close();
	}

}
